package com.gzc.just.play.last.war.common.distributed;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Service instance information
 */
public class ServiceInstance {
    private String serviceId;
    private String instanceId;
    private String serviceName;
    private String host;
    private int port;
    private String scheme;
    private Map<String, String> metadata;
    private long registrationTime;
    private int requestCount;
    private long lastAccessTime;
    private double loadFactor;
    
    public ServiceInstance() {
        this.scheme = "http";
        this.metadata = new ConcurrentHashMap<>();
        this.registrationTime = System.currentTimeMillis();
        this.lastAccessTime = System.currentTimeMillis();
        this.requestCount = 0;
        this.loadFactor = 0.0;
    }
    
    public ServiceInstance(String serviceId, String host, int port) {
        this(serviceId, serviceId, host, port);
    }
    
    public ServiceInstance(String serviceId, String host, int port, String scheme, Map<String, String> metadata, long registrationTime) {
        this(serviceId, serviceId, host, port, scheme, metadata, registrationTime);
    }
    
    public ServiceInstance(String instanceId, String serviceName, String host, int port) {
        this(instanceId, serviceName, host, port, "http", null, System.currentTimeMillis());
    }
    
    public ServiceInstance(String instanceId, String serviceName, String host, int port, String scheme,
                           Map<String, String> metadata, long registrationTime) {
        this();
        this.instanceId = instanceId;
        this.serviceName = serviceName;
        this.serviceId = instanceId != null ? instanceId : serviceName;
        this.host = host;
        this.port = port;
        if (scheme != null) {
            this.scheme = scheme;
        }
        if (metadata != null) {
            this.metadata = new ConcurrentHashMap<>(metadata);
        }
        this.registrationTime = registrationTime > 0 ? registrationTime : System.currentTimeMillis();
    }
    
    public String getUrl() {
        return scheme + "://" + host + ":" + port;
    }
    
    public void addMetadata(String key, String value) {
        metadata.put(key, value);
    }
    
    public String getMetadata(String key) {
        return metadata.get(key);
    }
    
    // Getters and setters
    public String getServiceId() {
        return serviceId;
    }
    
    public void setServiceId(String serviceId) {
        this.serviceId = serviceId;
    }
    
    public String getHost() {
        return host;
    }
    
    public void setHost(String host) {
        this.host = host;
    }
    
    public int getPort() {
        return port;
    }
    
    public void setPort(int port) {
        this.port = port;
    }
    
    public String getScheme() {
        return scheme;
    }
    
    public void setScheme(String scheme) {
        this.scheme = scheme;
    }
    
    public Map<String, String> getMetadata() {
        return metadata;
    }
    
    public void setMetadata(Map<String, String> metadata) {
        this.metadata = metadata != null ? new ConcurrentHashMap<>(metadata) : new ConcurrentHashMap<>();
    }
    
    public long getRegistrationTime() {
        return registrationTime;
    }
    
    public void setRegistrationTime(long registrationTime) {
        this.registrationTime = registrationTime;
    }
    
    public int getRequestCount() {
        return requestCount;
    }
    
    public void setRequestCount(int requestCount) {
        this.requestCount = requestCount;
    }
    
    public long getLastAccessTime() {
        return lastAccessTime;
    }
    
    public void setLastAccessTime(long lastAccessTime) {
        this.lastAccessTime = lastAccessTime;
    }
    
    public double getLoadFactor() {
        return loadFactor;
    }
    
    public void setLoadFactor(double loadFactor) {
        this.loadFactor = loadFactor;
    }
    
    public String getInstanceId() {
        return instanceId != null ? instanceId : serviceId;
    }
    
    public void setInstanceId(String instanceId) {
        this.instanceId = instanceId;
    }
    
    public String getServiceName() {
        return serviceName != null ? serviceName : serviceId;
    }
    
    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }
    
    // Load info inner class
    public static class LoadInfo {
        private final double loadFactor;
        private final int activeRequests;
        private final long lastAccessTime;
        
        public LoadInfo(double loadFactor, int activeRequests, long lastAccessTime) {
            this.loadFactor = loadFactor;
            this.activeRequests = activeRequests;
            this.lastAccessTime = lastAccessTime;
        }
        
        public double getLoadFactor() {
            return loadFactor;
        }
        
        public int getActiveRequests() {
            return activeRequests;
        }
        
        public long getLastAccessTime() {
            return lastAccessTime;
        }
    }
    
    public LoadInfo getLoadInfo() {
        return new LoadInfo(loadFactor, requestCount, lastAccessTime);
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        
        ServiceInstance that = (ServiceInstance) o;
        
        if (port != that.port) return false;
        if (!getInstanceId().equals(that.getInstanceId())) return false;
        if (!host.equals(that.host)) return false;
        return scheme.equals(that.scheme);
    }
    
    @Override
    public int hashCode() {
        int result = getInstanceId() != null ? getInstanceId().hashCode() : 0;
        result = 31 * result + host.hashCode();
        result = 31 * result + port;
        result = 31 * result + scheme.hashCode();
        return result;
    }
    
    @Override
    public String toString() {
        return "ServiceInstance{" +
                "instanceId='" + getInstanceId() + '\'' +
                ", serviceName='" + getServiceName() + '\'' +
                ", host='" + host + '\'' +
                ", port=" + port +
                ", scheme='" + scheme + '\'' +
                ", metadata=" + metadata +
                '}';
    }
}